#include "syscall.h"

int l1 = -1;
int c1 = -1;
int l2 = -1;
int c2 = -1;
int l3 = -1;
int c3 = -1;
int l4 = -1;
int c4 = -1;
int test = -1;

int threadcount = 0;

void waiting1(){
  Acquire(l1);
  Write ("Acquired l1\n", 12, ConsoleOutput);

  Write ("Wait on c1\n", 11, ConsoleOutput);

  Wait(l1, c1);

  Write ("Wait c1 Finished\n", 17, ConsoleOutput);

  Write ("Released l1\n", 12, ConsoleOutput);

  Release(l1);

  Exit(0);
}

void waiting2(){
  Acquire(l2);
  Write ("Acquired l2\n", 12, ConsoleOutput);

  Write ("Wait on c2\n", 11, ConsoleOutput);

  Wait(l2, c2);

  Write ("Wait c2 Finished\n", 17, ConsoleOutput);

  Write ("Released l2\n", 12, ConsoleOutput);
  Release(l2);

  Exit(0);
}

void waiting3(){

  Write ("Wait on c3\n", 11, ConsoleOutput);

  Wait(l1, c3);

  Exit(0);
}

void waiting4(){
  Acquire(l4);
  Write ("Acquired l4\n", 12, ConsoleOutput);

  Write ("Wait on c4\n", 11, ConsoleOutput);

  Wait(l4, c4);

  Write ("Wait c4 Finished\n", 17, ConsoleOutput);

  Write ("Released l4\n", 12, ConsoleOutput);
  Release(l4);

  Exit(0);
}

void signaling1(){
  Acquire(l1);

  Signal(l1, c1);

  Write("Signal c1\n", 10, ConsoleOutput);

  Release(l1);

  Exit(0);
}

void signaling2(){
  Acquire(l1);

  Write("Signal c4 with wrong lock\n", 26, ConsoleOutput);

  Signal(l1, c4);

  Release(l1);

  Exit(0);
}


void signaling3(){
  Acquire(l4);

  Write("Signal c4 with right lock\n", 26, ConsoleOutput);

  Signal(l4, c4);

  Release(l4);

  Exit(0);
}

void broad(){
  Acquire(l2);

  Broadcast(l2, c2);

  Write("Broadcast c2\n", 13, ConsoleOutput);

  Release(l2);

  Exit(0);
}

int main () {
  int i;
  Write ("Creating Variables\n", 19, ConsoleOutput);

  l1 =  CreateLock();
  c1 = CreateCondition();
  l2 =  CreateLock();
  c2 = CreateCondition();
  l3 =  CreateLock();
  c3 = CreateCondition();
  l4 =  CreateLock();
  c4 = CreateCondition();

  
  Write ("Testing Wait and Signal\n", 24, ConsoleOutput);

  Fork(waiting1);
  Fork(signaling1);

  Yield();

  Write ("Testing Wait and Broadcast\n", 27, ConsoleOutput);

  Fork(waiting2);
  Fork(waiting2);
  Fork(waiting2);
  Fork(waiting2);
  Fork(broad);
  
  Yield();

  Write ("Test when lock tries to wait with wrong lock\n", 45, ConsoleOutput);

  Fork (waiting3);

  Yield();

  Write ("Test when lock tries to signal with wrong lock\n", 47, ConsoleOutput);  Fork (waiting4);

  Fork (signaling2);
  Fork (signaling3);


  Exit(0);
}
